package com.huang.transport.socket.client;

import com.huang.loadbalancer.LoadBalancer;
import com.huang.loadbalancer.RandomLoadBalancer;
import com.huang.registry.NacosServiceDiscovery;
import com.huang.registry.ServiceDiscovery;
import com.huang.transport.RpcClient;
import com.huang.serializer.CommonSerializer;
import com.huang.transport.socket.util.ObjectReader;
import com.huang.transport.socket.util.ObjectWriter;
import com.huangwei.entity.RpcRequest;
import com.huangwei.entity.RpcResponse;
import com.huangwei.enumeration.RpcError;
import com.huangwei.exception.RpcException;
import com.huangwei.util.RpcMessageChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;

/*
远程调用的客户端消费者，socketbio方式，负责产生RpcRequest请求调用（具体实例对象通过动态代理生成）
 */
public class SocketRpcClient implements RpcClient {
    private static final Logger logger = LoggerFactory.getLogger(SocketRpcClient.class);
    private final ServiceDiscovery serviceDiscovery;
    private final CommonSerializer serializer;

    public SocketRpcClient(){
        this(DEFAULT_SERIALIZER, new RandomLoadBalancer());
    }

    public SocketRpcClient(LoadBalancer loadBalancer){
        this(DEFAULT_SERIALIZER, loadBalancer);
    }

    public SocketRpcClient(Integer serializer) {
        this(serializer, new RandomLoadBalancer());
    }
    public SocketRpcClient(Integer serializer, LoadBalancer loadBalancer){
        this.serviceDiscovery = new NacosServiceDiscovery(loadBalancer);
        this.serializer = CommonSerializer.getByCode(serializer);
    }

    //调用方法，将request对象传出，对接收到的response对象处理
    @Override
    public Object sendRequest(RpcRequest rpcRequest) {
        if (serializer == null){
            logger.error("未设置序列化器");
            throw new RpcException(RpcError.SERIALIZER_NOT_FOUND);
        }
        //从注册中心nacos获取调用的服务ip与端口号
        InetSocketAddress inetSocketAddress = serviceDiscovery.lookupService(rpcRequest.getInterfaceName());
        try (Socket socket = new Socket()){
            socket.connect(inetSocketAddress);
            OutputStream outputStream = socket.getOutputStream();
            InputStream inputStream = socket.getInputStream();
            ObjectWriter.writeObject(outputStream,rpcRequest,serializer);
            Object obj = ObjectReader.readObject(inputStream);
            RpcResponse rpcResponse = (RpcResponse) obj;

            if(rpcResponse==null){
                logger.error("服务调用失败，service：{}", rpcRequest.getInterfaceName());
                throw new RpcException(RpcError.SERVICE_INVOCATION_FAILURE, " service:" + rpcRequest.getInterfaceName());
            }
            RpcMessageChecker.check(rpcRequest,rpcResponse);
            return rpcResponse;
        }catch (IOException e) {
            logger.error("调用时有错误发生：", e);
            throw new RpcException("服务调用失败: ", e);
        }
    }

}
